#include <stdlib.h>
#include <glib.h>
#include <SDL.h>
#include "racanhack.h"
#include "task.h"
#include "video.h"
#include "cave.h"
#include "player.h"
#include "monster.h"
#include "monster2.h"
#include "floor.h"

static int monster_calc_id(int curf_level);
static struct _status monster_init_status(struct _monster *monster);
static void load_monster(int id, gchar *name, int mhp, int exp, int atk, int ac);

static int monster_calc_id(int curf_level)
{
  int candidate_id[10];
  int candidate_max;
  switch (curf_level) {
  case 0:
    candidate_id[0] = MONSTER_ID_SNAKE;
    candidate_id[1] = MONSTER_ID_BAT;
    candidate_max = 2;
    break;
  case 1:
    candidate_id[0] = MONSTER_ID_SNAKE;
    candidate_id[1] = MONSTER_ID_BAT;
    candidate_id[2] = MONSTER_ID_ORC;
    candidate_id[3] = MONSTER_ID_ICEMON;
    candidate_max = 4;
    break;
  case 2:
    candidate_id[0] = MONSTER_ID_SNAKE;
    candidate_id[1] = MONSTER_ID_BAT;
    candidate_id[2] = MONSTER_ID_ORC;
    candidate_id[3] = MONSTER_ID_ICEMON;
    candidate_max = 4;
    break;
  case 3:
    candidate_id[0] = MONSTER_ID_BAT;
    candidate_id[1] = MONSTER_ID_ORC;
    candidate_id[2] = MONSTER_ID_ICEMON;
    candidate_id[3] = MONSTER_ID_KOBOLD;
    candidate_max = 4;
    break;
  case 4:
    candidate_id[0] = MONSTER_ID_BAT;
    candidate_id[1] = MONSTER_ID_ORC;
    candidate_id[2] = MONSTER_ID_ICEMON;
    candidate_id[3] = MONSTER_ID_KOBOLD;
    candidate_id[4] = MONSTER_ID_ZOMBIE;
    candidate_max = 5;
    break;
  case 5:
    candidate_id[0] = MONSTER_ID_BAT;
    candidate_id[1] = MONSTER_ID_ORC;
    candidate_id[2] = MONSTER_ID_ICEMON;
    candidate_id[3] = MONSTER_ID_KOBOLD;
    candidate_id[4] = MONSTER_ID_ZOMBIE;
    candidate_max = 5;
    break;
  case 6:
    candidate_id[0] = MONSTER_ID_ICEMON;
    candidate_id[1] = MONSTER_ID_KOBOLD;
    candidate_id[2] = MONSTER_ID_ZOMBIE;
    candidate_max = 3;
    break;
  case 7:
    candidate_id[0] = MONSTER_ID_ICEMON;
    candidate_id[1] = MONSTER_ID_KOBOLD;
    candidate_id[2] = MONSTER_ID_ZOMBIE;
    candidate_max = 3;
    break;
  case 8:
    candidate_id[0] = MONSTER_ID_ICEMON;
    candidate_id[1] = MONSTER_ID_KOBOLD;
    candidate_id[2] = MONSTER_ID_ZOMBIE;
    candidate_id[3] = MONSTER_ID_HARPY;
    candidate_max = 4;
    break;
  case 9:
    candidate_id[0] = MONSTER_ID_ICEMON;
    candidate_id[1] = MONSTER_ID_KOBOLD;
    candidate_id[2] = MONSTER_ID_ZOMBIE;
    candidate_id[3] = MONSTER_ID_HARPY;
    candidate_id[4] = MONSTER_ID_CENTAUR;
    candidate_id[5] = MONSTER_ID_AQUATOR;
    candidate_max = 6;
    break;
  case 10:
    candidate_id[0] = MONSTER_ID_ICEMON;
    candidate_id[1] = MONSTER_ID_KOBOLD;
    candidate_id[2] = MONSTER_ID_ZOMBIE;
    candidate_id[3] = MONSTER_ID_HARPY;
    candidate_id[4] = MONSTER_ID_CENTAUR;
    candidate_id[5] = MONSTER_ID_AQUATOR;
    candidate_max = 6;
    break;
  case 11:
    candidate_id[0] = MONSTER_ID_ICEMON;
    candidate_id[1] = MONSTER_ID_KOBOLD;
    candidate_id[2] = MONSTER_ID_ZOMBIE;
    candidate_id[3] = MONSTER_ID_HARPY;
    candidate_id[4] = MONSTER_ID_CENTAUR;
    candidate_id[5] = MONSTER_ID_AQUATOR;
    candidate_max = 6;
    break;
  case 12:
    candidate_id[0] = MONSTER_ID_HARPY;
    candidate_id[1] = MONSTER_ID_NYMPH;
    candidate_id[2] = MONSTER_ID_CENTAUR;
    candidate_id[3] = MONSTER_ID_AQUATOR;
    candidate_id[4] = MONSTER_ID_GRIFFIN;
    candidate_max = 5;
    break;
  default:
    candidate_id[0] = MONSTER_ID_HARPY;
    candidate_id[1] = MONSTER_ID_NYMPH;
    candidate_id[2] = MONSTER_ID_CENTAUR;
    candidate_id[3] = MONSTER_ID_AQUATOR;
    candidate_id[4] = MONSTER_ID_GRIFFIN;
    candidate_id[5] = MONSTER_ID_DRAGON;
    candidate_max = 6;
    break;
  };
  return (candidate_id[g_random_int_range(0, candidate_max)]);
}

static struct _status monster_init_status(struct _monster *monster)
{
  struct _status status;
  switch (monster->id) {
  case MONSTER_ID_ICEMON:
    status.type = STATUS_SLEEP;
    status.time = G_MAXINT;
    break;
  default:
    if (g_random_int_range(0, 8) != 0) {
      status.type = STATUS_NORMAL;
      status.time = 0;
    } else {
      status.type = STATUS_SLEEP;
      status.time = G_MAXINT;
    };
    break;
  };
  return status;
}

struct _monster *monster_add()
{
  struct _monster *monster;
  monster = my_new(struct _monster, 1);
  monster->id = monster_calc_id(curf->level);
  monster->coord = rand_coord();
  monster->dir = DIR_2;
  monster->chp = monster_mhp(monster);
  monster->damage = 0;
  monster->status = monster_init_status(monster);
  monster->sprite = NULL;
  monster->task = NULL;
  curf->monster_list = g_list_append(curf->monster_list, monster);
  return (monster);
}

struct _monster *monster_add_monsterhouse(struct _coord c)
{
  struct _monster *monster;
  int id;
  monster = my_new(struct _monster, 1);
  id = monster_calc_id(curf->level);
  if (g_random_int_range(0, 5) == 0) {
    id += g_random_int_range(1, 3);
  };
  monster->id = CLAMP(id, 0, MONSTER_ID_MAX - 1);
  monster->coord = c;
  monster->dir = DIR_2;
  monster->chp = monster_mhp(monster);
  monster->damage = 0;
  monster->status.type = STATUS_SLEEP_MONSTERHOUSE;
  monster->status.time = 0;
  monster->sprite = NULL;
  monster->task = NULL;
  curf->monster_list = g_list_append(curf->monster_list, monster);
  return (monster);
}

gchar *monster_name(struct _monster *monster)
{
  return Monster_info[monster->id].name;
}

int monster_mhp(struct _monster *monster)
{
  return Monster_info[monster->id].mhp;
}

int monster_exp(struct _monster *monster)
{
  return Monster_info[monster->id].exp;
}

int monster_atk(struct _monster *monster)
{
  return Monster_info[monster->id].atk;
}

int monster_ac(struct _monster *monster)
{
  return Monster_info[monster->id].ac;
}

int monster_act(struct _monster *monster)
{
  int act = MONSTER_ACT_BITE;
  switch(monster->id) {
  case MONSTER_ID_ORC:
    act = MONSTER_ACT_HIT;
    break;
  case MONSTER_ID_ICEMON:
    if (g_random_int_range(0, 2) == 0) {
      act = MONSTER_ACT_CAST_SLEEP;
    } else {
      act = MONSTER_ACT_HIT;
    };
    break;
  case MONSTER_ID_KOBOLD:
    if (g_random_int_range(0, 4) == 0) {
      act = MONSTER_ACT_CAST_POISON;
    } else {
      act = MONSTER_ACT_CRAWL;
    };
    break;
  case MONSTER_ID_ZOMBIE:
    act = MONSTER_ACT_CRAWL;
    break;
  case MONSTER_ID_HARPY:
    if (g_random_int_range(0, 4) == 0) {
      act = MONSTER_ACT_CAST_TELEPORT;
    } else {
      act = MONSTER_ACT_CRAWL;
    };
    break;
  case MONSTER_ID_NYMPH:
    if (g_random_int_range(0, 2) == 0) {
      act = MONSTER_ACT_STEAL;
    } else {
      act = MONSTER_ACT_CRAWL;
    };
    break;
  case MONSTER_ID_AQUATOR:
    if (g_random_int_range(0, 4) == 0) {
      act = MONSTER_ACT_RUST_SHIELD;
    } else {
      act = MONSTER_ACT_HIT;
    };
    break;

  };
  return act;
}

static void load_monster(int id, gchar *name, int mhp, int exp, int atk, int ac)
{
  gchar buf[32];
  SDL_Surface *s;
  SDL_Rect r;
  int i, j;
  r.w = SPRITE_W; r.h = SPRITE_H;
  g_snprintf(buf, 32, "bmp/%s_idle.bmp", name);
  s = video_bmp_load(buf);
  for (i = 0; i < 8; i++) {
    for (j = 0; j < ANIME_J; j++) {
      r.x = SPRITE_W * j; r.y = SPRITE_H * i;
      surface_monster_idle[id][ddd(i)][j] = video_crop(s, &r);
    };
  };
  SDL_FreeSurface(s);
  g_snprintf(buf, 32, "bmp/%s_attack.bmp", name);
  s = video_bmp_load(buf);
  for (i = 0; i < 8; i++) {
    for (j = 0; j < ANIME_J; j++) {
      r.x = SPRITE_W * j; r.y = SPRITE_H * i;
      surface_monster_attack[id][ddd(i)][j] = video_crop(s, &r);
    };
  };
  SDL_FreeSurface(s);
  g_snprintf(buf, 32, "bmp/%s_damage.bmp", name);
  s = video_bmp_load(buf);
  for (i = 0; i < 8; i++) {
    for (j = 0; j < ANIME_J; j++) {
      r.x = SPRITE_W * j; r.y = SPRITE_H * i;
      surface_monster_damage[id][ddd(i)][j] = video_crop(s, &r);
    };
  };
  SDL_FreeSurface(s);
  g_snprintf(Monster_info[id].name, MONSTER_NAME_MAX_LENGTH, "%s", name);
  Monster_info[id].mhp = mhp;
  Monster_info[id].exp = exp;
  Monster_info[id].atk = atk;
  Monster_info[id].ac = ac;
}

void monster_init()
{
  load_monster(MONSTER_ID_SNAKE, "snake", 5, 1, 2, 1);
  load_monster(MONSTER_ID_BAT, "bat", 7, 2, 3, 1);
  load_monster(MONSTER_ID_ORC, "orc", 8, 8, 4, 9);
  load_monster(MONSTER_ID_ICEMON, "icemon", 12, 12, 6, 11);
  load_monster(MONSTER_ID_KOBOLD, "kobold", 14, 16, 6, 8);
  load_monster(MONSTER_ID_ZOMBIE, "zombie", 16, 20, 8, 19);
  load_monster(MONSTER_ID_HARPY, "harpy", 27, 25, 22, 16);
  load_monster(MONSTER_ID_NYMPH, "nymph", 40, 20, 0, 17);
  load_monster(MONSTER_ID_CENTAUR, "centaur", 35, 40, 15, 26);
  load_monster(MONSTER_ID_AQUATOR, "aquator", 30, 25, 0, 19);
  load_monster(MONSTER_ID_GRIFFIN, "griffin", 45, 50, 18, 27);
  load_monster(MONSTER_ID_TROLL, "troll", 52, 180, 32, 27);
  load_monster(MONSTER_ID_MANDRAGORA, "mandragora", 70, 30, 12, 23);
  load_monster(MONSTER_ID_PHANTOM, "phantom", 60, 150, 17, 27);
  load_monster(MONSTER_ID_DRAGON, "dragon", 100, 3000, 68, 30);
}

void monster_free()
{
  int id, i, j;
  for (id = 0; id < MONSTER_ID_MAX; id++) {
    for (i = 0; i < 8; i++) {
      for (j = 0; j < ANIME_J; j++) {
	SDL_FreeSurface(surface_monster_idle[id][ddd(i)][j]);
	SDL_FreeSurface(surface_monster_attack[id][ddd(i)][j]);
	SDL_FreeSurface(surface_monster_damage[id][ddd(i)][j]);
      };
    };
  };
}
